/**基于Promise，支持浏览器和node环境 */

// 配置参数：请求配置 > 实例配置 > 默认配置

// const instance = new axios()

// const instance = axios({})

// axios.get/post/delete/put

// instance.get/post/delete/put

// axios.interceptors.request.use(function,function)

// axios.interceptors.response.use(function,function)

// axios abort

export function axios() {
  return new Axios()
}

axios.get = function (...args) {
  return new Axios().get(args)
}

axios.post = function (...args) {
  return new Axios().post(args)
}

axios.delete = function (...args) {
  return new Axios().delete(args)
}

axios.put = function (...args) {
  return new Axios().put(args)
}

const requestInterceptors = []
const responseInterceptors = []
axios.interceptors = {
  request: {
    use: function (fn) {
      requestInterceptors.push(fn)
    }
  },
  response: {
    use: function (fn) {
      responseInterceptors.push(fn)
    }
  }
}

class Axios {
  requestInterceptors = []

  responseInterceptors = []

  request({ method, url, param, data, signal }) {
    const requestInterceptors = [
      ...this.requestInterceptors,
      ...requestInterceptors
    ]
    requestInterceptors.forEach(fn => {
      fn({ method, url, param, data })
    })
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest()
      url = createUrl(url, param)
      xhr.open(method, url)
      xhr.responseType = 'application/json'
      xhr.onload = function () {
        const responseInterceptors = [
          ...this.responseInterceptors,
          ...responseInterceptors
        ]
        responseInterceptors.forEach(fn => {
          fn(xhr.response)
        })
        resolve({
          data: xhr.response,
          status: xhr.status,
          toJson: JSON.parse
        })
      }
      signal.abort = xhr.abort
      xhr.onerror = function (err) {
        reject({
          message: err,
          status: xhr.status
        })
      }
      data = ['POST', 'PUT'].includes(method.toUpperCase()) ? data : null
      xhr.send(data)
    })
  }

  abort() {}

  get(...args) {
    assert(isObject(args), 'pamams need object!')
    this.request({ ...args, method: 'get' })
  }

  post(...args) {
    assert(isObject(args), 'pamams need object!')
    this.request({ ...args, method: 'post' })
  }

  delete(...args) {
    assert(isObject(args), 'pamams need object!')
    this.request({ ...args, method: 'delete' })
  }

  put(...args) {
    assert(isObject(args), 'pamams need object!')
    this.request({ ...args, method: 'delete' })
  }

  get interceptors() {
    const that = this
    return {
      request: {
        use: function (fn) {
          that.requestInterceptors.push(fn)
        }
      },
      response: {
        use: function (fn) {
          that.responseInterceptors.push(fn)
        }
      }
    }
  }
}

const assert = function (condition, msg) {
  if (!condition) {
    console.error(msg)
  }
}

const isObject = val => val && typeof val == 'object'

const isString = val => typeof val == 'string'

function createUrl(url, param) {
  if (!param) {
    return url
  }

  if (isObject(param)) {
    param = Object.keys(param)
      .map(key => {
        return `${key}=${param[key]}`
      })
      .join('&')
  }

  if (isString(param)) {
    return `${url}?${param}`
  }
}
